package com.songxh.core.config;

import com.alibaba.fastjson.JSONObject;
import com.songxh.core.base.CommonResult;
import com.songxh.core.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Method;
import java.util.Date;

/**
 * 统一日志打印切面
 *
 * @author songxh
 * @create 2023-01-12-14:06
 */
@Component
@Aspect  //这个注解在使用aop时使用，给类声明
@Slf4j
public class LogAspectConfig {
    //切入点，含义：对所有使用了@RestController 注解的类的所有方法
    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    public void logAop() {
    }

    @Around("logAop()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object[] args = point.getArgs();//方法的参数
        String param = "";
        try {
            //如果是传的文件流，那么便没必要将这些打印
            if (args != null && args[0] instanceof MultipartFile) {
                param = "MultipartFile";
            } else if (args != null) {
                param = JSONObject.toJSONString(args);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            param = e.getMessage();
        }
        //开始时间
        long startTime = System.currentTimeMillis();
        MethodSignature signature = (MethodSignature) point.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        //方法名
        String methodName = method.getName();
        //方法的路径
        String declaringTypeName = signature.getDeclaringTypeName();

        log.info("统一日志打印(start)，调用时间：{}，调用方法：{}.{}()，参数:{}", DateUtils.format(new Date(), DateUtils.DEFAULT_DATE_TIME_FORMAT), declaringTypeName, methodName, param);

        //执行方法。必须写该代码 否则无法执行切入的方法，因为使用的@Around注解，在执行方法前后调用
        Object response = point.proceed();

        //蠢方法，因为返回的结果不知道是什么类型，但是很多都是CommonResult类，所有这里就单独拿出来判断
        log.info("请求参数：{}", param);
        if (response.toString().contains("com.songxh.core.base.CommonResult")) {
            CommonResult result = (CommonResult) response;
            log.info("响应数据：{}", result.getData());
        }
        long totalTimeMillis = System.currentTimeMillis() - startTime;
        log.info("统一日志打印(end): 结束时间：{}，调用方法：{}.{}(),响应时间:{}毫秒", DateUtils.format(new Date(), DateUtils.DEFAULT_DATE_TIME_FORMAT), declaringTypeName, methodName, totalTimeMillis);
        return response;
    }
}
